home *** CD-ROM | disk | FTP | other *** search
- {
- ┌────────────────────────────────────────────┐
- │ OBINED.PAS │
- │ Object oriented for Version 6 Pascal │
- │ plus Kim Kokkonen's event handler tweak │
- │ see credits after end. │
- ╞════════════════════════════════════════════╡
- │ Vince Risi : Prodigy Computing (PTY) Ltd. │
- │ Compuserve [72427,3434] │
- │ Johannesburg, South Africa 886-7122 │
- └────────────────────────────────────────────┘
-
- ┌───────────────────────────────────────────────────────────────────────┐
- │You will need BINED.OBJ and EVENT.OBJ from the version 4 editor toolbox│
- │in order to compile this to a .tpu. │
- └───────────────────────────────────────────────────────────────────────┘
-
- }
- {$A-}
- {$I-}
- {$S-}
- {$R-}
-
- unit obined;
- {-The binary editor (of Borland) interface for Turbo Pascal version 6}
- interface
-
- const
- MaxFileSize = $FFE0; {Maximum file size editable by Binary Editor}
- EdOptInsert = $1; {Insert on flag}
- EdOptIndent = $2; {Autoindent on flag}
- EdOptTAB = $8; {Tab on flag}
- EdOptBlock = $10; {Show marked block}
- EdOptNoUpdate = $20; {Don't update screen when entering editor}
- EventKBflag = 1; {Scroll, num or caps locks modified mask}
- CAnorm = #255#1; {Activates CRT "normal" attribute}
- CAlow = #255#2; {Activates CRT "low" - }
- CAblk = #255#3; {Activates CRT "block" - }
- CAerr = #255#4; {Activates CRT "error" - }
- EdStatTextMod = 1; {Text buffer modified mask}
-
- type
- AttrArray = array[0..3] of Byte;
- ASCIIZ = array[0..255] of Char;
- ASCIIZptr = ^ASCIIZ;
- TextBuffer = array[0..$FFF0] of Char;
-
- EdintRecP = ^EdIntRec;
- EdIntRec = object
- function CurrLineOfs : Word;
- {-Return text buffer offset at start of current line}
- function CurrChar : Char;
- {-Return character at cursor position}
- function LinePos : Byte;
- {-Return cursor position within current line, 1..247}
- function LineLen : Byte;
- {-Return length of current line}
- function CurrLine : string;
- {-Return the current line as a string}
- function EditOptions : Byte;
- {-Return the current editor options}
- procedure ClearKbd;
- {-Clears both the BIOS and internal BINED keyboard buffers}
- procedure StuffKey(W : Word);
- {-Stuffs a keystroke into the keyboard buffer}
- private
- EditSeg : Word; {Segment where editor control block is located}
- BuffOfs : Word; {Offset in EditSeg where text buffer starts}
- LineOfs : Word; {Offset in EditSeg where offset of current line is stored}
- StrtOfs : Word; {Offset in EditSeg where line buffer is stored}
- CurrOfs : Word; {Offset in EditSeg where offset of position in line buffer is stored}
- CharOfs : Word; {Offset in EditSeg of character buffer}
- OptnOfs : Word; {Offset in EditSeg of editor options}
- procedure Find(var EdD);
- {-Initialize an internal data record}
- end;
-
- CRTinsStruct = record
- CRTtype : Byte; {1=IBM, 0=Non}
- CRTx1, CRTy1,
- CRTx2, CRTy2 : Byte; {Initial window size}
- CRTmode : Byte; {Initial mode 0-3,7 or FF(default)}
- CRTsnow : Byte; {0 if no snow, don't care for mono}
- AttrMono : AttrArray; {CRT attributes for mono mode}
- AttrBW : AttrArray; {CRT attributes for b/w modes}
- AttrColor : AttrArray; {CRT attributes for color modes}
- end;
- CIptr = ^CRTinsStruct;
-
- EdInsStruct = record
- ComTablen : Word; {Maximum length of command table}
- ComTab : TextBuffer; {Command table}
- end;
- EIptr = ^EdInsStruct;
-
- MIinsStruct = record
- Ver : Byte; {Main version}
- VerSub : Byte; {Sub version}
- VerPatch : Char; {Patch level}
- CPUmhz : Byte; {CPU speed for delays}
- CIstruct : CIptr; {Points to CRT installation record}
- EIstruct : EIptr; {Points to Editor installation area}
- DefExt : ASCIIZptr; {Points to ASCIIZ default extension}
- end;
- MIptr = ^MIinsStruct;
-
- EdCB = object
- constructor Init(
- DataLen : Word; {Size of binary editor workspace}
- Cx1 : Byte; {Editor window, upper left x 1..80}
- Cy1 : Byte; {Editor window, upper left y 1..25}
- Cx2 : Byte; {Editor window, lower right x 1..80}
- Cy2 : Byte; {Editor window, lower right y 1..25}
- WaitForRetrace : Boolean; {True for snowy color cards}
- Coptions : Word; {Initial editor options}
- DefExtension : string; {Default file extension (must start with period)}
- var ExitCommands; {Commands to exit editor}
- UserEventProcPtr: Pointer {Pointer to user event handler}
- );
- {-Innitialise an instance of the binary editor}
- {Fails if not enough memmory is available }
- function Read(Fname : string) : Word;
- {-Read a file into the binary editor buffer space,
- returning a status code}
- {
- Status codes -
- 0 = Successful read
- 1 = File not found, new file assumed
- 2 = File too large to edit
- }
- procedure Reset;
- {-Call the editor reset procedure}
- function Use(StartCommands : string) : Integer;
- {-Edit file, using startcommands, and returning an exitcode}
- {
- Exit codes -
- -1 = Editing terminated with ^KD
- 0 = Editing terminated with first user-specified exit command
- 1 ...
- }
- function Modified : Boolean;
- {-Return true if text buffer was modified during edit}
- function FileName : string;
- {-Return the current file pathname of the specified control block}
- procedure ChangeName(fname : string);
- {-rename pathname of the specified control block}
- function Save(MakeBackup : Boolean) : Word;
- {-Save the current file in the editor text buffer,
- returning a status code}
- {
- Status codes -
- 0 = Successful save
- 1 = File creation error
- 2 = Disk write error
- 3 = Error closing file
- }
- destructor Done;
- private
- x1, y1, x2, y2 : Byte; {Upper left and lower right corners of editor window}
- DataSeg : Word; {Segment address of editor data area}
- DataSegLen : Word; {Requested data area length (bytes)}
- Options : Word; {Bit flags for editor options}
- FileStr : ASCIIZptr; {Points to ASCIIZ filename}
- Commands : ASCIIZptr; {Points to ASCIIZ string of editor commands}
- Reserved1 : ASCIIZptr; {Not used here}
- Reserved2 : ASCIIZptr; {Not used here}
- Event : Pointer; {Points to event handling procedure}
- Buffer : ^TextBuffer;{Points to text area}
- BufSize : Word; {Available size for text}
- MIstruct : MIptr; {Points to main installation record}
- ComTab : ASCIIZptr; {Points to terminate command table}
- EOtext : Word; {Current number of chars in text buffer}
- CursorPos : Word; {Current cursor position in buffer}
- BlockStart : Word; {Start of marked block in buffer}
- BlockEnd : Word; {End of marked block in buffer}
- Status : Word; {Editor status}
- DataPtr : ^TextBuffer;{Points to Turbo heap block allocated for text buffer}
- Internals : edintrec; {points to internals}
- end;
-
- const
- {CRT attributes for normal low blk error}
- MonoArray : AttrArray = ($7, $70, $F, $F0);
- BwArray : AttrArray = ($7, $70, $F, $F0);
- ColorArray : AttrArray = ($1F, $38, $71, $4F);
-
- var
- CurrInternals : edintrecP;
-
- procedure CRTputFast(x, y : Word; s : string);
- {-Use binary editor services to write a string to the screen}
- {x in 1..25, y in 1..80}
-
- function ExpandPath(Fname : string) : string;
- {-Return a complete path using the binary editor services}
-
- implementation
-
- {$L BINED}
- procedure pAssign(var fromstr, tostr : ASCIIZ); external;
- procedure cCrtPutf(var s : ASCIIZ; r, c : Word); external;
- procedure EditInit(var EdData); external;
- procedure EditNew(var EdData); external;
- function Editor(var EdData) : Integer; external;
-
- var
- UserEventAddr : Pointer;
-
- {$L EVENT}
- procedure EventCheck(pinfo, peventno : Word); far; external;
-
- function AsciizToStr(a : ASCIIZ) : string;
- var
- s : string;
- slen : Byte absolute s;
- begin
- slen := 0;
- while a[slen] <> #0 do
- slen := Succ(slen);
- Move(a, s[1], slen);
- AsciizToStr := s;
- end;
-
- procedure StrToAsciiz(s : string; var a : ASCIIZ);
- var
- slen : Byte absolute s;
- begin {StrToAsciiz}
- Move(s[1], a, slen);
- a[slen] := #0;
- end; {StrToAsciiz}
-
- procedure CRTputFast(x, y : Word; s : String);
- var
- a : ASCIIZ;
- begin {CRTputFast}
- {Create ASCIIZ string}
- StrToAsciiz(s, a);
- cCrtPutf(a, Pred(y), Pred(x));
- end; {CRTputFast}
-
- function ExpandPath(Fname : String) : String;
- var
- fromstr, tostr : ASCIIZ;
-
- function StupCase(s : string) : string;
- var
- i : Word;
- begin {StupCase}
- for i := 1 to Length(s) do
- s[i] := UpCase(s[i]);
- StupCase := s;
- end; {StupCase}
-
- begin {ExpandPath}
- {Create ASCIIZ string from input}
- StrToAsciiz(Fname, fromstr);
- {Call the binary editor service}
- pAssign(fromstr, tostr);
- {Get Turbo string from Asciiz}
- ExpandPath := StupCase(AsciizToStr(tostr));
- end; {ExpandPath}
-
- constructor EdCB.Init(DataLen : Word; Cx1, Cy1, Cx2, Cy2 : Byte;
- WaitForRetrace : Boolean; Coptions : Word;
- DefExtension : String; var ExitCommands;
- UserEventProcPtr : Pointer);
- {-Initialize the binary editor, returning a status code}
- var
- nofs, bofs, codelen : Word;
- begin
- {Initialize the editor control block}
- DataSegLen := DataLen;
- if MaxAvail < DataSegLen then begin
- {Insufficient data space}
- fail;
- end;
- GetMem(DataPtr, DataSegLen+15);
- {Assure data space paragraph aligned}
- if Ofs(DataPtr^) <> 0 then
- DataSeg := Succ(Seg(DataPtr^))
- else
- DataSeg := Seg(DataPtr^);
- x1 := Pred(Cx1);
- x2 := Pred(Cx2);
- y1 := Pred(Cy1);
- y2 := Pred(Cy2);
- Options := Coptions;
- GetMem(FileStr, 72); {Space for max length file string}
- GetMem(Commands, 256); {Room for 255 bytes of startup keystrokes}
- FillChar(Commands^, 256, #0); {No startup commands right now}
- GetMem(Reserved1, 8); {Null out unused fields}
- FillChar(Reserved1^, 8, #0);
- Reserved2 := nil;
- if UserEventProcPtr = nil then
- {Disable event checking}
- Event := nil
- else begin
- {Set up for user event checking}
- Event := Addr(EventCheck);
- UserEventAddr := UserEventProcPtr;
- end;
- Buffer := nil; {Returned by Binary editor after initialization}
- BufSize := 0; {Returned by Binary editor after initialization}
- {Allocate and initialize main installation area}
- New(MIstruct);
- with MIstruct^ do begin
- Ver := 4;
- VerSub := 0;
- VerPatch := 'A'; {4.0A}
- CPUmhz := 5; {CPU speed in MHz - not critical}
- New(CIstruct);
- with CIstruct^ do begin
- CRTtype := 1;
- CRTx1 := 0;
- CRTy1 := 0;
- CRTx2 := 79;
- CRTy2 := 24; {Change to 42 for EGA 43 line mode}
- CRTmode := $FF; {Default screen mode}
- if WaitForRetrace then
- CRTsnow := $FF
- else
- CRTsnow := $0;
- AttrMono := MonoArray;
- AttrBW := BwArray;
- AttrColor := ColorArray;
- end;
- EIstruct := nil; {Command installation record set by Binary Editor}
- GetMem(DefExt, 8); {Default file extension}
- StrToAsciiz(DefExtension, DefExt^);
- end;
- {Install special exitcommands}
- ComTab := Addr(ExitCommands);
- {Position and status variables used by editor}
- EOtext := 0;
- CursorPos := 0;
- BlockStart := 0;
- BlockEnd := 0;
- Status := 0;
- {Call the binary editor initialization procedure}
- EditInit(x1);
- internals.Find(self);
- end; {InitBinaryEditor}
-
- function EdCB.Read(Fname : String) : Word;
- const
- ctrlz = #26;
- var
- f : file;
- fsize : longint;
- zpos, bytesread : Word;
- begin
- Fname := ExpandPath(Fname);
- StrToAsciiz(Fname, FileStr^);
- {See whether file exists}
- Assign(f, Fname);
- system.Reset(f, 1);
- if IOResult <> 0 then begin
- {Couldn't open file, assume a new one}
- EOtext := 0;
- Buffer^[EOtext] := #0;
- Read := 1;
- Exit;
- end;
- {Check the file size}
- fsize := FileSize(f);
- if fsize > BufSize then begin
- {File too big}
- Read := 2;
- Close(f);
- Exit;
- end;
- {Read the file}
- BlockRead(f, Buffer^, fsize, bytesread);
- Close(f);
- EOtext := fsize;
- {Scan for control Z in last sector of file}
- if EOtext < 512 then
- zpos := 0
- else
- zpos := EOtext-512;
- while zpos <> EOtext do
- if Buffer^[zpos] = ctrlz then
- EOtext := zpos
- else
- inc(zpos);
- Buffer^[EOtext] := #0;
- {Exit with success code}
- Read := 0;
- end;
-
- procedure EdCB.Reset;
- var junk : word; {!!}
- begin
- EditNew(x1);
- end;
-
- function EdCB.Use(StartCommands : String) : Integer;
- begin {UseBinaryEditor}
- CurrInternals := @Internals;
- {Put the start commands into the editor control block}
- if Length(StartCommands) > 0 then
- Move(StartCommands[1], Commands^, Length(StartCommands));
- {Call the editor}
- Use := Editor(x1);
- end; {UseBinaryEditor}
-
- function EdCB.Modified : Boolean;
- {-Return true if text buffer was modified during edit}
- begin {ModifiedFileBinaryEditor}
- Modified := (Status and EdStatTextMod) <> 0;
- end; {ModifiedFileBinaryEditor}
-
- function EdCB.FileName: String;
- {-Return the file name in the specified control block}
- begin {FileNameBinaryEditor}
- FileName := AsciizToStr(FileStr^);
- end; {FileNameBinaryEditor}
-
- procedure EdCB.ChangeName(fname : string);
- begin {FileNameBinaryEditor}
- {Expand the pathname and store it in editor control block}
- Fname := ExpandPath(Fname);
- StrToAsciiz(Fname, FileStr^);
- end;
-
- function EdCB.Save(MakeBackup : Boolean) : Word;
- {-Save the current file in the editor text buffer, returning a status code}
- var
- f : file;
- Fname : string;
- i, byteswritten : Word;
-
- function Exist(Fname : string; var f : file) : Boolean;
- {-Return true and assigned file handle if file exists}
- var
- i : Word;
- begin {Exist}
- Assign(f, Fname);
- System.Reset(f);
- Exist := (IOResult = 0);
- Close(f);
- {Clear ioresult}
- i := IOResult;
- end; {Exist}
-
- procedure MakeBakFile(NewName : string);
- {-Make a backup file}
- var
- nf, bf : file;
- BakName : string;
- DotPos : Byte;
- C : Char;
-
- begin {MakeBakFile}
- if Exist(NewName, nf) then begin
- {Workfile already exists, back it up}
- {Find position of last period in NewName}
- DotPos := Succ(Length(NewName));
- repeat
- dec(DotPos);
- C := NewName[DotPos];
- until (C = '.') or (C = '\') or (C = ':') or (DotPos = 0);
- if (dotpos = 0) or (C <> '.') then
- bakname := newname+'.BAK'
- else
- bakname := Copy(NewName, 1, dotpos)+'BAK';
- if Exist(bakname, bf) then
- {Backup already exists, erase it}
- Erase(bf);
- {Rename existing file to backup}
- Rename(nf, bakname);
- end;
- end; {MakeBakFile}
-
- begin {SaveFileBinaryEditor}
- Fname := AsciizToStr(FileStr^);
- if MakeBackup then
- MakeBakFile(Fname);
- Assign(f, Fname);
- Rewrite(f, 1);
- if IOResult <> 0 then begin
- Save := 1;
- Close(f);
- i := IOResult; {Clear ioresult}
- Exit;
- end;
- BlockWrite(f, Buffer^, Succ(EOtext), byteswritten);
- if (byteswritten <> Succ(EOtext)) or (IOResult <> 0) then begin
- Save := 2;
- Close(f);
- Exit;
- end;
- Close(f);
- if IOResult <> 0 then begin
- Save := 3;
- Exit;
- end;
- {Reset editor modified bit}
- Status := 0;
- {Success status}
- Save := 0;
- end;
-
- destructor edcb.done;
- {-Release heap space used by a binary editor control block}
- begin {ReleaseBinaryEditorHeap}
- FreeMem(DataPtr, DataSegLen+15);
- FreeMem(FileStr, 72);
- FreeMem(Commands, 256);
- FreeMem(Reserved1, 8);
- Dispose(MIstruct^.CIstruct);
- FreeMem(MIstruct^.DefExt, 8);
- Dispose(MIstruct);
- end;
-
- const
- KbdStart = $1E;
- KbdEnd = $3C;
- type
- Barray = array[0..30000] of Byte;
- BarrayPtr = ^Barray;
- SO =
- record
- O : Word;
- S : Word;
- end;
- var
- KbdHead : Word absolute $40 : $1A;
- KbdTail : Word absolute $40 : $1C;
-
- function Search(var Buffer; BuffLen : Word;
- var Match; MatchLen : Word) : Pointer;
- {-Return pointer to start of match, nil if none}
- var
- B : BarrayPtr;
- M : BarrayPtr;
- I : Word;
- J : Word;
- Matched : Boolean;
- begin
- B := @Buffer;
- M := @Match;
- for I := 1 to BuffLen do begin
- if B^[0] = M^[0] then begin
- {Start of a match, try the rest}
- if MatchLen = 1 then
- Matched := True
- else begin
- J := 1;
- repeat
- Matched := (B^[J] = M^[J]);
- Inc(J);
- until not Matched or (J = MatchLen);
- end;
- if Matched then begin
- {Complete match}
- Search := B;
- Exit;
- end;
- end;
- {Move to next byte}
- Inc(SO(B).O);
- end;
- {No match}
- Search := nil;
- end;
-
- function CodeMatch(B, M : BarrayPtr; Len : Word) : Boolean;
- {-Return true if B^ matches M^ after discounting addresses}
- var
- MB : Byte;
- I : Word;
- begin
- for I := 0 to Len-1 do begin
- MB := M^[I];
- if MB <> 0 then
- if MB <> B^[I] then begin
- CodeMatch := False;
- Exit;
- end;
- end;
- CodeMatch := True;
- end;
-
- procedure EdintRec.Find(var EdD);
- {-Initialize an internal data record}
- type
- WordPtr = ^Word;
- const
- {Code we must find to determine data offsets}
- Match0 : array[0..7] of Byte =
- ($C3, {RET}
- $C3, {RET}
- $F6, $06, $00, $00, $01, {TEST [Options],01}
- $C3); {RET}
- Match1 : array[0..18] of Byte =
- ($C6, $07, $1A, {MOV BYTE PTR [BX],1Ah}
- $8B, $16, $00, $00, {MOV DX,[LineOfs]}
- $2B, $16, $00, $00, {SUB DX,[BuffOfs]}
- $BE, $00, $00, {MOV SI,StrtOfs}
- $FC, {CLD}
- $3B, $36, $00, $00); {CMP SI,[CurrOfs]}
- Match2 : array[0..7] of Byte =
- ($5B, {POP BX}
- $80, $3E, $00, $00, $FF, {CMP [BufChar],$FF}
- $B0, $FF); {MOV AL,$FF}
- var
- EdData : Edcb absolute EdD;
- B0 : BarrayPtr;
- B1 : BarrayPtr;
- B2 : BarrayPtr;
- begin
- {All zeros will indicate error}
- FillChar(self, SizeOf(self), 0);
-
- {B0 is base of the binary editor code segment}
- B0 := Ptr(Seg(EditInit), 0);
-
- {Find code for editor options}
- B0 := Search(B0^, 10000, Match0, 4);
- if B0 = nil then
- {Not found}
- Exit;
- if not CodeMatch(B0, @Match0, SizeOf(Match0)) then
- {Not a complete match}
- Exit;
-
- {Find code for various buffer offsets}
- B1 := Search(B0^, 10000, Match1, 5);
- if B1 = nil then
- Exit;
- if not CodeMatch(B1, @Match1, SizeOf(Match1)) then
- Exit;
-
- {Find code for character buffer}
- B2 := Search(B1^, 10000, Match2, 3);
- if B2 = nil then
- Exit;
- if not CodeMatch(B2, @Match2, SizeOf(Match2)) then
- Exit;
-
- {Initialize the internals record}
- EditSeg := EdData.DataSeg;
- BuffOfs := SO(EdData.Buffer).O;
- OptnOfs := WordPtr(@B0^[4])^;
- LineOfs := WordPtr(@B1^[5])^;
- StrtOfs := WordPtr(@B1^[12])^;
- CurrOfs := WordPtr(@B1^[17])^;
- CharOfs := WordPtr(@B2^[3])^;
- end;
-
- function Edintrec.CurrLineOfs : Word;
- {-Return text buffer offset of start of current line}
- begin
- if EditSeg = 0 then
- CurrLineOfs := $FFFF
- else
- CurrLineOfs := MemW[EditSeg:LineOfs]-BuffOfs;
- end;
-
- function Edintrec.CurrChar : Char;
- {-Return character at cursor position}
- begin
- if EditSeg = 0 then
- CurrChar := #$FF
- else
- CurrChar := Char(Mem[EditSeg:MemW[EditSeg:CurrOfs]]);
- end;
-
- function Edintrec.LinePos : Byte;
- {-Return cursor position within current line}
- begin
- if EditSeg = 0 then
- LinePos := $FF
- else
- LinePos := MemW[EditSeg:CurrOfs]-StrtOfs+1;
- end;
-
- function Edintrec.LineLen : Byte;
- {-Return length of current line}
- var
- O : Word;
- begin
- if EditSeg = 0 then
- LineLen := $FF
- else begin
- O := StrtOfs+247;
- while (O >= StrtOfs) and (Mem[EditSeg:O] = $20) do
- Dec(O);
- LineLen := O+1-StrtOfs;
- end;
- end;
-
- function Edintrec.CurrLine : string;
- {-Return the current line as a string}
- var
- L : string;
- LL : Byte absolute L;
- begin
- LL := LineLen;
- if LL = $FF then
- LL := 0
- else
- Move(Mem[EditSeg:StrtOfs], L[1], LL);
- CurrLine := L;
- end;
-
- function Edintrec.EditOptions : Byte;
- {-Return the current editor options}
- begin
- if EditSeg = 0 then
- EditOptions := $FF
- else
- EditOptions := Mem[EditSeg:OptnOfs];
- end;
-
- procedure Edintrec.ClearKbd;
- {-Clears both the BIOS and internal BINED keyboard buffers}
- begin
- if EditSeg <> 0 then begin
- {Clear BIOS keyboard buffer}
- KbdHead := KbdTail;
- {Clear BINED character buffer}
- Mem[EditSeg:CharOfs] := $FF;
- end;
- end;
-
- procedure Edintrec.StuffKey(W : Word);
- {-Stuffs a keystroke into the keyboard buffer}
- var
- SaveKbdTail : Word;
- begin
- SaveKbdTail := KbdTail;
- if KbdTail = KbdEnd then
- KbdTail := KbdStart
- else
- Inc(KbdTail, 2);
- if KbdTail = KbdHead then
- {Buffer full, ignore request}
- KbdTail := SaveKbdTail
- else
- MemW[$40:SaveKbdTail] := W;
- end;
-
- end.
- ________________________________________________________________________________
- { BINED.PAS
- BINED 4.0
- Copyright (c) 1985, 87 by Borland International, Inc. }
- {
- BININT offers a way to access normally hidden information while within a
- BINED event handler. See BININT.DOC for details. (follows)
-
- Written by Kim Kokkonen, TurboPower Software.
- Released to the public domain.
- Compuserve [72457,2131]
-
- Version 1.0, 10/22/88
- first release
- }
- BININT
- Accessing BINED Internal Information in Event Handlers
- Version 1.0
- Kim Kokkonen
-
- Overview
- ------------------------------------------------------------------------------
- BININT is a small unit that may be used in programs based on the binary
- editor, BINED, from Borland's Editor Toolbox. It removes a drawback of BINED,
- which is that accurate information about the cursor position (within the
- current line and text buffer) is not available to event handlers. As such,
- event handlers are limited in what they can do.
-
- When accurate information is available to a BINED event handler, new
- horizons open up for using the binary editor. We developed this unit in
- order to add limited mouse support to BINED, which required knowing the
- cursor position relative to the overall file size. Another popular request
- is to add word-wrap to BINED -- knowing the information provided by BININT, an
- event handler could be written to add word wrap.
-
- BININT is a dirty little unit, peeking into the BINED code segment to read
- certain offsets of data items that it needs to compute accurate information
- for use by an event handler. Even so, BININT is very careful to assure that
- the information it uses is correct. If BININT can't find the appropriate
- offsets, it will fail gracefully, but in this case an event handler won't
- have the information it needs. So far this isn't much of a concern since to
- our knowledge Borland has released only a single version of BINED. BININT is
- designed to adjust itself automatically whenever possible, even if BINED is
- changed in the future.
-
- In the following, we assume you know what is meant by a BINED "event handler".
- See Borland's documentation, or the supplied example TEST.PAS, for background.
-
-
- Using BININT
- ------------------------------------------------------------------------------
- Just add BININT to your USES list, after BINED itself. (BININT depends on
- BINED.) Then your application can call any of the following procedures and
- functions.
-
- procedure FindInternals(EdData : EdCB; var E : EdIntRec);
-
- Call FindInternals any time after calling Borland's InitBinaryEditor
- routine, but before calling UseBinaryEditor. This routine initializes the
- record parameter E to hold information needed to track the specified edit
- window EdData. The program must declare a global variable of type EdIntRec
- to store the binary editor internals information for use by the event
- handler. Note that you will need a separate EdIntRec variable for each
- BINED edit window.
-
- If for some reason BININT cannot find the appropriate locations in BINED, it
- will return all fields of the EdIntRec set to zero. This may be considered
- a critical error for any program using BININT even though the rest of
- BININT's functions are designed to return safe values in this case. You can
- test for correct operation of FindInternals with the following statement:
-
- if E.EditSeg = 0 then
- {Critical error, unknown BINED version} ;
-
- The remaining BININT functions are intended for use within an event handler.
- Each of them requires a parameter of type EdIntRec, previously initialized by
- a call to FindInternals.
-
- function CurrLineOfs(var E : EdIntRec) : Word;
-
- This routine returns the byte offset within BinEd's text buffer of the first
- character on the current line. For example, if the cursor is on the first
- line of a text file, CurrLineOfs will return 0. If the first line has 10
- characters (counting CR and LF), then CurrLineOfs will return 10 when the
- cursor is on the second line of the file. When the cursor is moved to the
- end of the file, CurrLineOfs returns the same value as EdData.EOtext. If the
- EdIntRec was not correctly initialized, CurrLineOfs returns $FFFF.
-
- Note that CurrLineOfs does not vary when the cursor is moved within a given
- line. The LinePos function provides that information.
-
- function CurrChar(var E : EdIntRec) : Char;
-
- CurrChar returns the ASCII character associated with the current cursor
- position in the file. If the cursor is beyond the end of the current line,
- CurrChar returns a blank (#32). CurrChar will not return a CR (#13), LF
- (#10), or EOF (#26) unless the text file is corrupt. If the EdIntRec was not
- correctly initialized, CurrChar returns #255.
-
- function LinePos(var E : EdIntRec) : Byte;
-
- LinePos returns the position of the cursor in the current line. It returns 1
- for the first character in the line. The highest value normally returned
- will be 249. If the EdIntRec was not correctly initialized, LinePos returns
- 255.
-
- Note that you can't add LinePos to CurrLineOfs and obtain an offset that
- means anything. BINED copies the current line to a separate buffer for
- editing and recopies it to the main text buffer only when the cursor leaves
- the line. Hence, the contents of the text buffer beyond CurrLineOfs are not
- guaranteed to be up to date. Use the CurrLine function to get the contents
- of the current text line.
-
- function LineLen(var E : EdIntRec) : Byte;
-
- Returns the length of the current line. The length is defined as the number
- of characters up to and including the last non-blank character in the line.
- Note that the cursor is allowed to move beyond this position, and thus you
- will have situations where LinePos > LineLen. If the EdIntRec was not
- correctly initialized, LineLen returns 255.
-
- function CurrLine(var E : EdIntRec) : string;
-
- Returns the current text line as a string. There's no need to call LineLen
- if you call CurrLine since the length of the returned string equals LineLen.
- If the EdIntRec was not correctly initialized, CurrLine returns an empty
- string.
-
- function EditOptions(var E : EdIntRec) : Byte;
-
- Returns the current value of the editor options (which may have been changed
- by the user since the edit session started). See the constants near the top
- of BINED.PAS (EdOptInsert and so on) for masks to decode this bit-mapped
- byte.
-
- Note that BININT is not designed to let you _modify_ any of the data that it
- provides. Within an event handler, it is not safe to change the cursor
- position, or directly modify the line buffer.
-
- If modification of the text stream is desired (as would be the case when
- adding word wrap to BINED), the appropriate action is to poke characters into
- the keyboard buffer. For this reason, BININT provides two more procedures:
-
- procedure ClearKbd(var E : EdIntRec);
-
- Before poking a character, it is best to call this routine. ClearKbd clears
- not only the BIOS keyboard buffer, but also an internal single byte buffer
- used by BINED to hold extended keystrokes.
-
- procedure StuffKey(W : Word);
-
- This stuffs one character (ASCII value with scan code) into the keyboard
- buffer. If the character is not extended (like <F1> or <Left>) it is alright
- to call StuffKey as follows:
-
- StuffKey(Ord(CharToStuff));
-
- For example
-
- StuffKey(Ord(^M));
-
- puts a carriage return into the keyboard buffer, to be acted upon by BINED
- when the event handler returns.
-
- For an extended character, pass the appropriate word value. For example
-
- StuffKey($4B00);
-
- stuffs a <Left> arrow into the keyboard buffer.
-
- Remember that the keyboard buffer normally holds only 16 characters. If the
- buffer is full when StuffKey is called, it does nothing.
-
-
- Examples
- ------------------------------------------------------------------------------
- The supplied program TEST1.PAS is a tiny example of using BININT. It allows
- you to browse through a file while continuously showing a status report of the
- information offered by BININT. Just compile TEST1.PAS and run it by specifying
- a text file to browse on the command line:
-
- TEST1 FileToBrowse
-
- Press ^KD to quit. No changes will be saved.
-
- TEST2 is a frivolous example of modifying the text stream by stuffing
- characters into the keyboard buffer. Compile and run it just like TEST1. In
- TEST2, whenever the cursor is positioned over a space within a text line, the
- event handler breaks the text onto the next line, leading to a
- semi-interactive "one word per line" filter. If the editor is in overwrite
- mode, the event handler does nothing. Like TEST1, TEST2 does not allow you to
- save the resulting file.
-
-
- Disclaimer
- ------------------------------------------------------------------------------
- The BININT unit was written by Kim Kokkonen of TurboPower Software. It is
- hereby released to the public domain. We accept no liability for the use of
- this software, and make no guarantees as to its performance. Good luck! We'd
- like to hear from the first person to develop a word-wrapping event handler
- for BINED.
-